<?php
/**
 * @link https://www.kancloud.cn/cleverstone/ymb2
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

namespace builder\widget\ajax;

use builder\helper\H5;
use builder\widget\BaseWidget;
use yii\helpers\Html;

/**
 * Ajax:多媒体列表
 * ```php
 * MediaList::widget([
 *      'media' => 'image/abcd.jpg',
 *      'mediaOption' => [
 *          'style' => [
 *              'width' => '50px',
 *              'height' => '50px',
 *          ],
 *      ],
 *      'mediaHeader' => function () use ($brandLabel, $specType, $row) {
 *          return $brandLabel . "\n" . $specType . "\n" . H5::encode($row['title']);
 *      },
 *      'mediaBody' => [
 *          [
 *              'ID：' => $row['id'],
 *              '库存：' => $row['stocks'],
 *              '销量：' => $row['sales'],
 *          ]
 *      ],
 *      'mediaList' => [
 *          [
 *              '售价：' => $row['price'],
 *              '市场价：' => function () use ($row) {
 *                      return H5::text($row['o_price'], ['style' => [
 *                          'text-decoration' => 'line-through',
 *                          'color' => 'red',
 *                       ]]);
 *              },
 *              '邮费：' => $row['postage'],
 *          ],
 *      ],
 * ]);
 * ```
 * @author cleverstone
 * @since ym2.0
 */
class MediaList extends BaseWidget
{
    /**
     * @var array
     */
    public $options = [];

    /**
     * @var string|array 媒体
     */
    public $media;
    public $mediaIsImage = true;
    public $mediaOption = [];

    /**
     * @var string 媒体标题
     */
    public $mediaHeader;
    public $mediaHeaderOption = [];

    /**
     * @var array 媒体内容
     */
    public $mediaBody = [];
    public $mediaBodyOption = [];

    /**
     * @var array 媒体列表
     */
    public $mediaList = [];
    public $mediaListOption = [];

    /**
     * Initializes the object.
     * This method is called at the end of the constructor.
     * The default implementation will trigger an [[EVENT_INIT]] event.
     */
    public function init()
    {
        parent::init();
        $this->initOption();
    }

    /**
     * @throws \Throwable
     */
    public function run()
    {
        if (
            $this->media
            || $this->mediaHeader
            || $this->mediaBody
            || $this->mediaList
        ) {
            //:1
            echo Html::beginTag('div', $this->options). "\n";
            if (
                $this->media
                || $this->mediaHeader
                || $this->mediaBody
            ) {
                //:2
                echo Html::beginTag('div', ['class' => 'media']). "\n";
                // Media Image
                echo $this->renderMedia() . "\n";
                if ($this->mediaHeader || $this->mediaBody) {
                    //Media Header And Media Body
                    echo Html::beginTag('div', $this->mediaBodyOption) . "\n";
                    echo $this->renderMediaHeader() . "\n";
                    echo $this->renderMediaBody($this->mediaBody) . "\n";
                    echo Html::endTag('div') . "\n";
                }
                //:2
                echo Html::endTag('div') . "\n";
            }

            if (
                $this->mediaList
                && (
                    $this->media
                    || $this->mediaHeader
                    || $this->mediaBody
                )
            ) {
                //Media Divider
                echo Html::tag('div', '', ['class' => 'py-1']) . "\n";
            }

            if ($this->mediaList) {//Media List
                echo Html::beginTag('div', $this->mediaListOption) . "\n";
                echo $this->renderMediaList($this->mediaList) . "\n";
                echo Html::endTag('div') . "\n";
            }

            //:1
            echo Html::endTag('div') . "\n";
        } else {
            echo '';
        }
    }

    /**
     * 初始化配置
     */
    protected function initOption()
    {
        Html::addCssClass($this->options, ['widget-media', 'widget' => 'f13']);

        if (!empty($this->media) && $this->mediaIsImage) {
            $this->media = (array)$this->media;
            Html::addCssStyle($this->mediaOption, ['width' => '70px', 'height' => '70px'], false);
        }

        if ($this->mediaHeader !== null) {
            Html::addCssClass($this->mediaHeaderOption, ['media-header', 'widget' => 'f15']);
        }

        Html::addCssClass($this->mediaBodyOption, ['media-body', 'widget' => 'f13']);
        Html::addCssClass($this->mediaListOption, ['media-list', 'widget' => 'f13']);
    }

    /**
     * @return string
     * @throws \Throwable
     */
    protected function renderMedia()
    {
        if (empty($this->media)) {
            return null;
        }

        if (!$this->mediaIsImage) {
            return Html::tag('div', $this->media, $this->mediaOption);
        }

        $options = [];
        $additionalStyle = Html::cssStyleToArray($this->mediaOption['style']);
        $options['style'] = ['width' => $additionalStyle['width']];
        $options['ym2-full-image'] = '';
        foreach ($this->media as &$link) {
            $link = H5::img($link, $options);
        }

        Html::addCssClass($this->mediaOption, ['layout' => 'img-flex-style mr-3']);
        if (count($this->media) == 1) {//One Item
            return Html::tag('div', implode("\n", $this->media), $this->mediaOption);
        } else {//Many Item
            $this->mediaOption['ym2-image-group'] = '';
            $config = [
                'options' => $this->mediaOption,
                'controls' => false,
                'items' => $this->media,
            ];
            Carousel::$autoIdPrefix = 'ML-Carousel';
            return Carousel::widget($config);
        }
    }

    /**
     * @return string
     */
    protected function renderMediaHeader()
    {
        if ($this->mediaHeader !== null) {
            $mediaHeader = $this->mediaHeader;
            if (is_callable($mediaHeader)) {
                $mediaHeader = call_user_func($mediaHeader);//使用闭包动态计算结果，并且信任结果内容。
            } else {
                $mediaHeader = H5::encode($mediaHeader);//防止xss注入
            }
            return Html::tag('div', $mediaHeader, $this->mediaHeaderOption);
        } else {
            return null;
        }
    }

    /**
     * @param array $mediaBody
     * @return string
     */
    protected function renderMediaBody(array $mediaBody)
    {
        if (!empty($mediaBody)) {
            $result = '';
            foreach ($mediaBody as $key => $value) {
                if ($this->isEmpty($value)) {
                    continue;
                }

                $result .= Html::beginTag('div', ['class' => 'media--line']);

                if (!is_int($key)) {
                    $result .= $this->getInlineBlockDiv($key, ['class' => 'media--line_label']);
                }

                if (is_array($value)) {
                    $result .= $this->renderMediaBodyLine($value);
                } else {
                    $result .= $this->getInlineBlockDiv($value, ['class' => 'media--line_item']);
                }

                $result .= Html::endTag('div');
            }

            return $result;
        } else {
            return null;
        }
    }

    /**
     * @param array $mediaBody
     * @return string
     */
    protected function renderMediaBodyLine(array $mediaBody)
    {
        if (!empty($mediaBody)) {
            $result = '';
            foreach ($mediaBody as $key => $value) {
                if ($this->isEmpty($value)) {
                    continue;
                }

                if (!is_int($key)) {
                    $result .= $this->getInlineBlockDiv($key, ['class' => 'media--line_label']);
                }

                if (is_array($value)) {
                    $result .= $this->renderMediaBodyLine($value);
                } else {
                    $result .= $this->getInlineBlockDiv($value, ['class' => 'media--line_item']);
                }
            }

            return $result;
        } else {
            return null;
        }
    }

    /**
     * @param array $mediaList
     * @return string
     */
    protected function renderMediaList(array $mediaList)
    {
        if (!empty($mediaList)) {
            $result = '';
            foreach ($mediaList as $key => $value) {
                if ($this->isEmpty($value)) {
                    continue;
                }

                $result .= Html::beginTag('div', ['class' => 'media--line']);
                if (!is_int($key)) {
                    $result .= $this->getInlineBlockDiv($key, ['class' => 'media--line_label']);
                }

                if (is_array($value)) {
                    $result .= $this->renderMediaListLine($value);
                } else {
                    $result .= $this->getInlineBlockDiv($value, ['class' => 'media--line_item']);
                }

                $result .= Html::endTag('div');
            }

            return $result;
        } else {
            return null;
        }
    }

    /**
     * @param array $mediaList
     * @return string
     */
    protected function renderMediaListLine(array $mediaList)
    {
        if (!empty($mediaList)) {
            $result = '';
            foreach ($mediaList as $key => $value) {
                if ($this->isEmpty($value)) {
                    continue;
                }

                if (!is_int($key)) {
                    $result .= $this->getInlineBlockDiv($key, ['class' => 'media--line_label']);
                }

                if (is_array($value)) {
                    $result .= $this->renderMediaListLine($value);
                } else {
                    $result .= $this->getInlineBlockDiv($value, ['class' => 'media--line_item']);
                }
            }

            return $result;
        } else {
            return null;
        }
    }

    /**
     * @param string $content
     * @param array $option
     * @return string
     */
    private function getInlineBlockDiv($content, $option = [])
    {
        if ($this->isEmpty($content)) {
            return '';
        }

        if (is_callable($content)) {
            $content = call_user_func($content);//使用闭包动态计算结果，并且信任结果内容。
        } else {
            $content = H5::encode($content);//防止xss注入
        }

        return Html::tag('div', $content, $option);
    }

    /**
     * 是否为空
     * @param mixed $result
     * @return bool
     */
    protected function isEmpty($result)
    {
        return $result === null || $result === '' || $result === [];
    }
}